﻿using System;
using System.Collections.Specialized;
using Agnes.Core;
using DevExpress.XtraScheduler;
using System.Collections.ObjectModel;
using Csla;
using Csla.Rules.CommonRules;
using System.Xml.Linq;

namespace Agnes.TaskManager
{
    /// <summary>
    /// 任务
    /// </summary>
    [Serializable]
    public class Task : ModelBase<Task>
    {
        #region Csla属性

        /// <summary>
        /// Id
        /// </summary>
        public static readonly PropertyInfo<Guid> IdProperty = RegisterProperty<Guid>(c => c.Id);
        /// <summary>
        /// Id
        /// </summary>
        public Guid Id
        {
            get { return GetProperty(IdProperty); }
            set { SetProperty(IdProperty, value); }
        }

        /// <summary>
        /// 开始时间
        /// </summary>
        public static readonly PropertyInfo<DateTime> StartDTProperty = RegisterProperty<DateTime>(c => c.StartDT);
        /// <summary>
        /// 开始时间
        /// </summary>
        public DateTime StartDT
        {
            get { return GetProperty(StartDTProperty); }
            set { SetProperty(StartDTProperty, value); }
        }

        /// <summary>
        /// 结束时间
        /// </summary>
        public static readonly PropertyInfo<DateTime> EndDTProperty = RegisterProperty<DateTime>(c => c.EndDT);
        /// <summary>
        /// 结束时间
        /// </summary>
        public DateTime EndDT
        {
            get { return GetProperty(EndDTProperty); }
            set { SetProperty(EndDTProperty, value); }
        }

        /// <summary>
        /// 主题
        /// </summary>
        public static readonly PropertyInfo<string> SubjectProperty = RegisterProperty<string>(c => c.Subject);
        /// <summary>
        /// 主题
        /// </summary>
        public string Subject
        {
            get { return GetProperty(SubjectProperty); }
            set { SetProperty(SubjectProperty, value); }
        }

        /// <summary>
        /// 是否全天事件
        /// </summary>
        public static readonly PropertyInfo<bool> IsAllDayProperty = RegisterProperty<bool>(c => c.IsAllDay);
        /// <summary>
        /// 是否全天事件
        /// </summary>
        public bool IsAllDay
        {
            get { return GetProperty(IsAllDayProperty); }
            set { SetProperty(IsAllDayProperty, value); }
        }

        /// <summary>
        /// 描述
        /// </summary>
        public static readonly PropertyInfo<string> DescriptionProperty = RegisterProperty<string>(c => c.Description);
        /// <summary>
        /// 描述
        /// </summary>
        public string Description
        {
            get { return GetProperty(DescriptionProperty); }
            set { SetProperty(DescriptionProperty, value); }
        }

        /// <summary>
        /// 子任务
        /// </summary>
        public static readonly PropertyInfo<ObservableCollection<Task>> ChildsProperty = RegisterProperty<ObservableCollection<Task>>(c => c.Childs);
        /// <summary>
        /// 子任务
        /// </summary>
        public ObservableCollection<Task> Childs
        {
            get { return GetProperty(ChildsProperty); }
            set { SetProperty(ChildsProperty, value); }
        }

        /// <summary>
        /// 是否是任务类别
        /// </summary>
        public static readonly PropertyInfo<bool> IsTaskCatagoryProperty = RegisterProperty<bool>(c => c.IsTaskCatagory);
        /// <summary>
        /// 是否是任务类别
        /// </summary>
        public bool IsTaskCatagory
        {
            get { return GetProperty(IsTaskCatagoryProperty); }
            private set { LoadProperty(IsTaskCatagoryProperty, value); }
        }

        /// <summary>
        /// 完成率
        /// </summary>
        public static readonly PropertyInfo<int> ProgressProperty = RegisterProperty<int>(c => c.Progress);
        /// <summary>
        /// 完成率
        /// </summary>
        public int Progress
        {
            get { return GetProperty(ProgressProperty); }
            set { SetProperty(ProgressProperty, value); }
        }

        /// <summary>
        /// LabelId
        /// </summary>
        public static readonly PropertyInfo<int> LabelIdProperty = RegisterProperty<int>(c => c.LabelId);
        /// <summary>
        /// LabelId
        /// </summary>
        public int LabelId
        {
            get { return GetProperty(LabelIdProperty); }
            set { SetProperty(LabelIdProperty, value); }
        }

        /// <summary>
        /// 任务状态
        /// </summary>
        public static readonly PropertyInfo<TaskStatus> TaskStatusProperty = RegisterProperty<TaskStatus>(c => c.TaskStatus);
        /// <summary>
        /// 任务状态
        /// </summary>
        public TaskStatus TaskStatus
        {
            get { return GetProperty(TaskStatusProperty); }
            set { SetProperty(TaskStatusProperty, value); }
        }

        /// <summary>
        /// 父任务
        /// </summary>
        public static readonly PropertyInfo<Task> ParentTaskProperty = RegisterProperty<Task>(c => c.ParentTask);
        /// <summary>
        /// 父任务
        /// </summary>
        public Task ParentTask
        {
            get { return GetProperty(ParentTaskProperty); }
            set { SetProperty(ParentTaskProperty, value); }
        }

        /// <summary>
        /// 是否启用循环
        /// </summary>
        public static readonly PropertyInfo<bool> IsRecurrenceProperty = RegisterProperty<bool>(c => c.IsRecurrence);
        /// <summary>
        /// 是否启用循环
        /// </summary>
        public bool IsRecurrence
        {
            get { return GetProperty(IsRecurrenceProperty); }
            set { SetProperty(IsRecurrenceProperty, value); }
        }

        /// <summary>
        /// 循环信息
        /// </summary>
        public static readonly PropertyInfo<string> RecurrenceInfoProperty = RegisterProperty<string>(c => c.RecurrenceInfo);
        /// <summary>
        /// 循环信息
        /// </summary>
        public string RecurrenceInfo
        {
            get { return GetProperty(RecurrenceInfoProperty); }
            set { SetProperty(RecurrenceInfoProperty, value); }
        }

        public static readonly PropertyInfo<string> ReminderInfoProperty = RegisterProperty<string>(c => c.ReminderInfo);
        /// <summary>
        /// 提醒信息(会有两个默认触发器，一个是任务结束前，一个是任务开始)
        /// </summary>
        public string ReminderInfo
        {
            get { return GetProperty(ReminderInfoProperty); }
            set { SetProperty(ReminderInfoProperty, value); }
        }

        public static readonly PropertyInfo<int> AlertTimeProperty = RegisterProperty<int>(c => c.AlertTime);
        /// <summary>
        /// 提醒分钟数
        /// </summary>
        public int AlertTime
        {
            get { return GetProperty(AlertTimeProperty); }
            set { SetProperty(AlertTimeProperty, value); }
        }

        public static readonly PropertyInfo<int> AppTypeProperty = RegisterProperty<int>(c => c.AppType);
        /// <summary>
        /// 提醒分钟数
        /// </summary>
        public int AppType
        {
            get { return GetProperty(AppTypeProperty); }
            set { SetProperty(AppTypeProperty, value); }
        }


        #endregion

        #region Csla方法

        public Task()
        {
        }

        private XElement GetXml()
        {
            XElement el = new XElement("Task",
                new XAttribute("Id", Id),
                new XAttribute("Subject", Subject),
                new XAttribute("StartDT", StartDT.ToString("yyyy/MM/dd HH:mm")),
                new XAttribute("EndDT", EndDT.ToString("yyyy/MM/dd HH:mm")),
                new XAttribute("IsAllDay", IsAllDay.ToString()),
                new XAttribute("Description", Description),
                new XAttribute("Progress", Progress),
                new XAttribute("LabelId", LabelId),
                new XAttribute("TaskStatus", TaskStatus.ToString()),
                new XAttribute("RecurrenceInfo", RecurrenceInfo),
                new XAttribute("ReminderInfo", ReminderInfo),
                new XAttribute("AlertTime", AlertTime));

            foreach (Task i in Childs)
            {
                i.SaveToXml(el.Add);
            }

            return el;
        }

        /// <summary>
        /// SaveToXml
        /// </summary>
        /// <param name="Save"></param>
        public void SaveToXml(Action<XElement> Save)
        {
            DataPortal.UpdateChild(this);
            Save(GetXml());
        }

        protected override void DoCreate(object createParam)
        {
            base.DoCreate(createParam);
            using (BypassPropertyChecks)
            {
                Id = Guid.NewGuid();
                AppType = 1;
                Childs = new ObservableCollection<Task>();
                Subject = "新增任务 ";
                IsTaskCatagory = false;
                StartDT = DateTime.Now.AddMinutes(2);
                EndDT = DateTime.Now.AddMinutes(30);
                Description = "无备注";
                RecurrenceInfo recurrenceInfo = new RecurrenceInfo(DateTime.Now, 1);
                recurrenceInfo.Range = RecurrenceRange.OccurrenceCount;
                RecurrenceInfo = recurrenceInfo.ToXml();
                AlertTime = 0;
                
                Childs.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(TasksChildChanged);
            }
            BusinessRules.CheckRules(AlertTimeProperty);
        }

        protected override void DoFetch(object fetchParam)
        {
            XElement el = fetchParam as XElement;

            using (BypassPropertyChecks)
            {
                AppType = 1;
                Id = Guid.Parse(el.Attribute("Id").Value.ToString());
                Subject = el.Attribute("Subject").Value;
                StartDT = DateTime.Parse(el.Attribute("StartDT").Value);
                EndDT = DateTime.Parse(el.Attribute("EndDT").Value);
                IsAllDay = Boolean.Parse(el.Attribute("IsAllDay").Value);
                Description = el.Attribute("Description").Value;
                Progress = Int32.Parse(el.Attribute("Progress").Value);
                AlertTime = Int32.Parse(el.Attribute("AlertTime").Value);
                LabelId = Int32.Parse(el.Attribute("LabelId").Value);
                RecurrenceInfo = el.Attribute("RecurrenceInfo").Value;
                ReminderInfo = el.Attribute("ReminderInfo").Value;
                TaskStatus = (TaskStatus)Enum.Parse(typeof(TaskStatus), el.Attribute("TaskStatus").Value);
                Childs = new ObservableCollection<Task>();
                Childs.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(TasksChildChanged);

                foreach (XElement childEl in el.Elements("Task"))
                {
                    Childs.Add(Task.FetchAsChild(childEl));
                }
            }
            base.DoFetch(fetchParam);
        }

        public override void Delete()
        {
            if (ParentTask == null)
            {
                AgnesServiceManager.LogServ.Error("该任务节点是根节点不能被删除");
            }
            ParentTask.Childs.Remove(this);
        }

        #endregion

        #region 数据验证

        protected override void AddBusinessRules()
        {
            base.AddBusinessRules();
            AddStartDTRule();
            AddEndDTRule();
            AddSubjectRule();
            AddIsAllDayRule();
            AddStatusRule();
            AddProgressRule();
            AddAlertTimeRule();
        }

        private void AddAlertTimeRule()
        {
            var r = new Lambda(AlertTimeProperty, t =>
            {
                Task h = t.Target as Task;
            });

            BusinessRules.AddRule(r);
        }

        private void AddProgressRule()
        {
            var r = new Lambda(ProgressProperty, t =>
            {
                Task h = t.Target as Task;
                if (h.Progress == 100)
                {
                    h.TaskStatus = TaskStatus.Finished;
                }
                RefleshData();
                if (h.ParentTask != null)
                {
                    h.ParentTask.ReflashProgress();
                }
            });

            BusinessRules.AddRule(r);
        }

        private void AddStatusRule()
        {
            var r = new Lambda(TaskStatusProperty, t =>
            {
                Task h = t.Target as Task;

                if (h.Childs.Count == 0)
                {
                    if (h.TaskStatus == TaskStatus.Finished
                        || h.TaskStatus == TaskStatus.Abandon
                        || h.TaskStatus == TaskStatus.PostProgress)
                    {
                        h.Progress = 100;
                    }
                    else if (h.TaskStatus == TaskStatus.InProgress)
                    {
                        if (h.ParentTask != null)
                        {
                            h.Progress = 50;
                            h.ParentTask.ReflashProgress();
                            h.ParentTask.TaskStatus = TaskStatus.InProgress;
                        }
                    }
                }
            });

            BusinessRules.AddRule(r);
        }

        private void AddStartDTRule()
        {
            var r = new Lambda(StartDTProperty, t =>
            {
                Task h = t.Target as Task;
                h.BusinessRules.CheckRules(EndDTProperty);
            });

            BusinessRules.AddRule(r);
            OnPropertyChanged(StartDTProperty);
        }

        private void AddEndDTRule()
        {
            var r = new Lambda(EndDTProperty, t =>
            {
                Task h = t.Target as Task;
                if ((h.EndDT - h.StartDT).Ticks < 0)
                {
                    t.AddErrorResult(EndDTProperty, "开始时间不能晚于结束时间");
                }
                else
                {
                    if (h.ParentTask != null)
                    {
                        h.ParentTask.RefleshData();
                    }
                }
            });

            BusinessRules.AddRule(r);
        }

        private void AddSubjectRule()
        {
            var r = new Lambda(SubjectProperty, t =>
            {
                Task h = t.Target as Task;
                if (h.Subject == "")
                {
                    t.AddErrorResult("请填写一个主题");
                }
            });

            BusinessRules.AddRule(r);
        }

        private void AddIsAllDayRule()
        {
            var r = new Lambda(IsAllDayProperty, t =>
            {
                Task h = t.Target as Task;
                if (h.IsAllDay)
                {
                    h.StartDT.AddHours(-h.StartDT.Hour);
                    h.StartDT.AddMinutes(-h.StartDT.Minute);
                    h.EndDT = h.StartDT;
                    t.AddInformationResult(IsAllDayProperty, "默认以开始时间为标准的一天");
                }
            });

            BusinessRules.AddRule(r);
        }

        #endregion

        #region 其他

        public void ReflashProgress()
        {
            double finished = 0;
            foreach (Task i in Childs)
            {
                finished += i.Progress;
            }

            this.Progress = (int)((finished / Childs.Count));

            if (ParentTask != null)
            {
                ParentTask.ReflashProgress();
            }
        }

        /// <summary>
        /// 根据子任务重新计算这条任务的数据
        /// 并促发父任务也进行更新
        /// </summary>
        public void RefleshData()
        {
            if (Childs.Count == 0)
            {
                if (this.ParentTask != null)
                {
                    this.ParentTask.RefleshData();
                }
            }
            else
            {
                StartDT = Childs[0].StartDT;
                EndDT = Childs[0].EndDT;
                foreach (Task i in Childs)
                {
                    if ((i.StartDT - StartDT).Ticks < 0)
                    {
                        StartDT = i.StartDT;
                        OnPropertyChanged(StartDTProperty);
                    }
                    if ((EndDT - i.EndDT).Ticks < 0)
                    {
                        EndDT = i.EndDT;
                        OnPropertyChanged(StartDTProperty);
                    }
                }

                if (this.ParentTask != null)
                {
                    this.ParentTask.RefleshData();
                }
            }
        }

        private void TasksChildChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (Childs.Count != 0)
            {
                IsTaskCatagory = true;
            }
            else
            {
                IsTaskCatagory = false;
            }

            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                if (TaskManagerService.TaskManager != null)
                {
                    if (TaskManagerService.TaskManager.LeafTasks.IndexOf(this) != -1)
                    {
                        TaskManagerService.TaskManager.LeafTasks.Remove(this);
                    }
                    foreach (Task item in e.NewItems)
                    {
                        TaskManagerService.TaskManager.LeafTasks.Add(item);

                        item.ParentTask = this;
                        item.BusinessRules.CheckRules(TaskStatusProperty);
                    }

                    RefleshData();
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (Task oldItem in e.OldItems)
                {
                    oldItem.BusinessRules.CheckRules(TaskStatusProperty);
                    if (TaskManagerService.TaskManager.LeafTasks.IndexOf(oldItem) != -1)
                    {
                        TaskManagerService.TaskManager.LeafTasks.Remove(oldItem);
                    }
                }
                
                if (Childs.Count == 0)
                {
                    TaskManagerService.TaskManager.LeafTasks.Add(this);
                }
                RefleshData();
            }

            this.BusinessRules.CheckRules(TaskStatusProperty);
            OnPropertyChanged(ChildsProperty);
        }

        public override Task Save()
        {
            OnPropertyChanged(ReminderInfoProperty);
            OnPropertyChanged(StartDTProperty);
            OnPropertyChanged(EndDTProperty);
            DataPortal.Update<Task>(this);
            return base.Save();
        }


        #endregion
    }
}
